/* Copyright 2020 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "osal_io.h"
#include "osal_mem.h"


#define HDF_LOG_TAG demo_sample

/* HdfDriverEntry method definitions */
static int32_t SampleDemoDriverBind(struct HdfDeviceObject *device);
static int32_t SampleDemoDriverInit(struct HdfDeviceObject *device);
static void SampleDemoDriverRelease(struct HdfDeviceObject *device);

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_sampleDemoDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "DEMO_SAMPLE",
    .Bind = SampleDemoDriverBind,
    .Init = SampleDemoDriverInit,
    .Release = SampleDemoDriverRelease,
};

// Initialize HdfDriverEntry
HDF_INIT(g_sampleDemoDriverEntry);

/* DemoHostMethod method definitions */
static int32_t SampleDemoHostInit(struct DemoHost *host);
static int32_t SampleDemoHostDeinit(struct DemoHost *host);
static int32_t SampleDemoHostWrite(struct DemoHost *host, uint8_t *data, uint32_t size);

/* DemoHostMethod definitions */
struct DemoHostMethod g_sampleDemoHostMethod = {
    .Init = SampleDemoHostInit,
    .Deinit = SampleDemoHostDeinit,
    .Read = NULL,
    .Write = SampleDemoHostWrite,
};

/* DemoHostMethod implementations */
static int32_t SampleDemoHostInit(struct DemoHost *host)
{
    HDF_LOGD("%s: Enter", __func__);
    if (host == NULL) {
        HDF_LOGW("%s: invalid parameter", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

static int32_t SampleDemoHostDeinit(struct DemoHost *host)
{
    HDF_LOGD("%s: Enter", __func__);
    if (host == NULL) {
        HDF_LOGW("%s: invalid parameter", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

static int32_t SampleDemoHostWrite(struct DemoHost *host, uint8_t *data, uint32_t size)
{
    uint32_t idx;
    struct DemoDevice *device = NULL;
    HDF_LOGD("%s: Enter", __func__);

    if (host == NULL || data == NULL || size == 0) {
        HDF_LOGW("%s: invalid parameter", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    device = (struct DemoDevice *)host->priv;
    if (device == NULL) {
        HDF_LOGW("%s: device is NULL", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

static int InitDemoDevice(struct DemoDevice *device)
{
    device->state = DEMO_DEVICE_INITIALIZED;
    return HDF_SUCCESS;
}

static uint32_t GetDemoDeviceResource(
    struct DemoDevice *device, const struct DeviceResourceNode *resourceNode)
{
    struct DemoResource *resource = &device->resource;
    struct DeviceResourceIface *dri = NULL;
    dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (dri == NULL || dri->GetUint32 == NULL) {
        HDF_LOGE("DeviceResourceIface is invalid");
        return HDF_FAILURE;
    }

    if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
        HDF_LOGE("demo config read num fail");
        return HDF_FAILURE;
    }
	// 不同类型属性获取的函数不一样
    return HDF_SUCCESS;
}

static int32_t AttachDemoDevice(struct DemoHost *host, struct HdfDeviceObject *device)
{
    int32_t ret;
    struct DemoDevice *demoDevice = NULL;
    if (device->property == NULL) {
        HDF_LOGW("%s: property is NULL", __func__);
        return HDF_FAILURE;
    }
    demoDevice = (struct DemoDevice *)OsalMemCalloc(sizeof(struct DemoDevice));
    if (demoDevice == NULL) {
        HDF_LOGE("%s: OsalMemCalloc demoDevice error", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }
    ret = GetDemoDeviceResource(demoDevice, device->property);
    if (ret != HDF_SUCCESS) {
        (void)OsalMemFree(demoDevice);
        return HDF_FAILURE;
    }
    host->num = demoDevice->resource.num;
    host->priv = demoDevice;
    AddDemoDevice(host);
    return InitDemoDevice(demoDevice);
}

static void DeinitDemoDevice(struct DemoDevice *device)
{
    device->state = DEMO_DEVICE_UNINITIALIZED;
}

static void DetachDemoDevice(struct DemoHost *host)
{
    struct DemoDevice *demoDevice = NULL;

    if (host->priv == NULL) {
        HDF_LOGW("%s: invalid parameter", __func__);
        return;
    }
    demoDevice = host->priv;
    DeinitDemoDevice(demoDevice);
    (void)OsalMemFree(demoDevice);
    host->priv = NULL;
}

/* HdfDriverEntry implementations */
static int32_t SampleDemoDriverBind(struct HdfDeviceObject *device)
{
    struct DemoHost *demoHost = NULL;
    HDF_LOGD("%s: Enter", __func__);

    if (device == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }

    demoHost = DemoHostCreate(device);
    if (demoHost == NULL) {
        HDF_LOGE("%s: DemoHostCreate failed", __func__);
        return HDF_FAILURE;
    }
    demoHost->service.Dispatch = SampleDispatch;
    return HDF_SUCCESS;
}

static int32_t SampleDemoDriverInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct DemoHost *host = NULL;
    HDF_LOGD("%s: Enter", __func__);

    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }
    host = DemoHostFromDevice(device);
    if (host == NULL) {
        HDF_LOGE("%s: host is NULL", __func__);
        return HDF_FAILURE;
    }
    ret = AttachDemoDevice(host, device);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: attach error", __func__);
        return HDF_FAILURE;
    }
    host->method = &g_sampleDemoHostMethod;
    return ret;
}

static void SampleDemoDriverRelease(struct HdfDeviceObject *device)
{
    struct DemoHost *host = NULL;
    HDF_LOGD("%s: Enter", __func__);

    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return;
    }
    host = DemoHostFromDevice(device);
    if (host == NULL) {
        HDF_LOGE("%s: host is NULL", __func__);
        return;
    }
    if (host->priv != NULL) {
        DetachDemoDevice(host);
    }
    DemoHostDestroy(host);
}
